﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace The_LarX
{
    public class LarConsole : GuideLikeComponent
    {
        public string Text;

        public Dictionary<string, Type> CommandsTypes;

        public List<string> Console;

        public int MaxConsoleLinesStored = 200;

        protected Keys[] TextKeys = new Keys[]
        {
            // Default Keyboard Keys
            Keys.A, Keys.B, Keys.C, Keys.D, Keys.E, Keys.F, Keys.G,
            Keys.H, Keys.I, Keys.J, Keys.K, Keys.L, Keys.M, Keys.N,
            Keys.O, Keys.P, Keys.Q, Keys.R, Keys.S, Keys.T, Keys.U,
            Keys.V, Keys.W, Keys.X, Keys.Y, Keys.Z,             
            // Symbols
            Keys.OemComma, Keys.OemPeriod, Keys.OemPlus, Keys.OemMinus,
            Keys.Space, Keys.Back, Keys.Enter, Keys.Divide, Keys.OemQuestion,
            Keys.Multiply, Keys.Add, Keys.Subtract,
            // Numbers
            Keys.D0, Keys.D1, Keys.D2, Keys.D3, Keys.D4, Keys.D5,
            Keys.D6, Keys.D7, Keys.D8, Keys.D9
        };

        public LarConsole()
        {
            this.NeedToBlockUpdate = true;

            CommandsTypes = new Dictionary<string, Type>();
            Console = new List<string>();

            CommandsTypes.Add("quit", typeof(cmd_Quit));
            CommandsTypes.Add("reset", typeof(cmd_Reset));
        }

        protected Keys holdingKey;
        protected int holdingKTimer;
        protected int startRepeatingTime = 300;
        protected bool holded;
        protected int alreadyHoldedTimer;
        protected int alreadyHoldedTime = 100;

        protected int LastIndex;
        public override void Update()
        {
            Keys[] keys = Engine.Input.CurrentKeyboardStates[0].GetPressedKeys();

            if (Engine.Input.IsKeyboardPress(Keys.Up))
            {
                if (Console.Count > LastIndex)
                {
                    Text = Console[LastIndex++];
                }
            }
            if (Engine.Input.IsKeyboardPress(Keys.Down))
            {
                if (LastIndex > 0)
                {
                    LastIndex--;
                    Text = Console[LastIndex];
                }
            }

            if (keys.Length > 0)
            {
                for (int i = 0; i < keys.Length; i++)
                {
                    if (TextKeys.Contains(keys[i]))
                    {
                        if (Engine.Input.IsKeyboardPress(keys[i]))
                        {
                            // Perfect Key
                            string key = keys[i].ToString();

                            CheckAndPutKey(key);
                        }
                        else
                        {
                            if (holdingKey == keys[i])
                            {
                                holdingKTimer += Engine.GameTime.ElapsedGameTime.Milliseconds;
                                if (holdingKTimer > startRepeatingTime)
                                {
                                    if (!holded)
                                    {
                                        holded = true;
                                        CheckAndPutKey(holdingKey.ToString());
                                    }
                                    else
                                    {
                                        alreadyHoldedTimer += Engine.GameTime.ElapsedGameTime.Milliseconds;
                                        if (alreadyHoldedTimer > alreadyHoldedTime)
                                        {
                                            alreadyHoldedTimer = 0;
                                            holded = false;
                                        }
                                    }
                                }
                            }
                            else
                            {
                                holded = false;
                                holdingKey = keys[i];
                                holdingKTimer = 0;
                            }
                        }
                    }                    
                }
            }
        }
        private void CheckAndPutKey(string key)
        {
            if (key.Length > 1)
            {
                // Must be a simple or whatever
                string keyl = key.ToLower();
                if (keyl == "oemperiod")
                    Text += ".";
                else if (keyl == "oemminus" || key == "subtract")
                    Text += "-";
                else if (keyl == "oemplus" || key == "add")
                    Text += "+";
                else if (keyl == "multiply")
                    Text += "*";
                else if (keyl == "space")
                    Text += " ";
                else if (keyl == "back")
                {
                    if (Text.Length >= 1)
                    {
                        Text = Text.Remove(Text.Length - 1);
                    }
                }
                else if (keyl == "enter")
                {
                    ExecuteCommand();
                }
                else if (keyl == "divide")
                    Text += "/";
                else if (keyl == "oemquestion")
                    Text += "?";
                else if (keyl.StartsWith("d"))
                    Text += int.Parse(keyl[1].ToString());
            }
            else
            {
                if (Engine.Input.IsKeyboardUp(Keys.LeftShift) &&
                    Engine.Input.IsKeyboardUp(Keys.RightShift))
                    key = key.ToLower();

                Text += key;
            }
        }

        public void ExecuteCommand()
        {
            try
            {
                LastIndex = 0;
                // Here the Magic happens
                Console.Insert(0, Text);
                string[] textSplitted = Text.Split(' ');
                string command = textSplitted[0].ToLower();
                if (command == "set" || command == "get")
                {
                    command = (textSplitted[0] + ' ' + textSplitted[1]).ToLower();
                }
                if (CommandsTypes.ContainsKey(command))
                {
                    Type t = CommandsTypes[command];
                    ConsoleCommand obj = (ConsoleCommand)Activator.CreateInstance(t);
                    obj.Console = this;
                    if (Text.Contains("/?"))
                    {
                        obj.GetUsage(Text);
                    }
                    else
                    {
                        obj.Do(Text);
                    }
                }
                else
                {
                    Console.Insert(0, LanguageManager.GetEngineString(10));
                }
                Text = "";
            }
            catch { }
        }

        public void InsertLine(string line)
        {
            Console.Insert(0, line);
        }

        protected bool UnderlineShow;
        protected int Timer;
        protected int TimeToUnderline = 500;
        public override void Draw()
        {
            Timer += Engine.GameTime.ElapsedGameTime.Milliseconds;
            if (Timer > TimeToUnderline)
            {
                Timer = 0;
                UnderlineShow = !UnderlineShow;
            }
            Color gray = Color.Black;
            gray.A = 230;
            PresentationParameters pp = Engine.GraphicsDevice.PresentationParameters;
            Engine.RenderManager.DrawRectangle(gray, new Rectangle(0, 0, pp.BackBufferWidth, pp.BackBufferHeight / 3), null);
            string underline = "";
            if (UnderlineShow)
                underline = "_";
            float X = (pp.BackBufferWidth / 20);
            Engine.RenderManager.DrawString(Engine.RenderManager.DivideString(Text + underline, 1280 - X, "LucidaConsole12"), 0, 0,
                new Vector2((pp.BackBufferWidth / 20), 
                    ((pp.BackBufferHeight / 3) - (pp.BackBufferHeight / 10))),
                    "LucidaConsole12", Color.White, null, 0, Vector2.Zero, 1, 0);
            float Y = 0;
            for (int i = 0; i < 10; i++)
            {
                if (Console.Count > i)
                {
                    Vector2 stringSize = Engine.FontManager.GetFont("LucidaConsole12").MeasureString(Console[i]);
                    Y += stringSize.Y;
                    Engine.RenderManager.DrawString(Engine.RenderManager.DivideString(Console[i], 1280 - X, "LucidaConsole12"), 0, 0,
                    new Vector2(X,
                        ((pp.BackBufferHeight / 3) - (pp.BackBufferHeight / 10) - (Y))),
                        "LucidaConsole12", Color.White, null, 0, Vector2.Zero, 1, 0);
                }
            }
        }
    }
}

